
#include "json_value.h"

namespace json
{
	value value::_null = value();

	value::value(void) 
		: _type(null), 
		_data((int*)malloc(4)), 
		_allocated(4) 
	{
	}
	value::value(bool a) 
		: _type(boolean), 
		_data((int*)malloc(4)), 
		_allocated(4)
	{	
		_data[0] = a;
	}
	value::value(float a) 
		: _type(number), 
		_data((int*)malloc(4)),
		_allocated(4) 
	{
		((float*)_data)[0] = a;
	}
	value::value(const char * a) 
		: _type(string), 
		_data((int*)malloc(4)), 
		_allocated(4) 
	{
		_data[0] = reinterpret_cast<int>(new str(a));
	}
	value::value(const str & a) 
		: _type(string), 
		_data((int*)malloc(4)),
		_allocated(4) 
	{
		_data[0] = reinterpret_cast<int>(new str(a));
	}
	value::value(const char * a, const value & v) 
		: _type(object)
	{
		_data = (int*)malloc(16);
		_allocated = 16;
		_data[0] = 1;
		_data[1] = reinterpret_cast<int>(new str(a));
		_data[2] = reinterpret_cast<int>(new value(v));
	}
	value::value(const str & a, const value & v) 
		: _type(object)
	{
		_data = (int*)malloc(16);
		_allocated = 16;
		_data[0] = 1;
		_data[1] = reinterpret_cast<int>(new str(a));
		_data[2] = reinterpret_cast<int>(new value(v));
	}
	value::value(const value & a)
	{
		_type = a._type;
		_allocated = a._allocated;
		_data = (int*)malloc(a._allocated);
		if (isObject())
		{
			_data[0] = a._data[0];
			for (int i = 1; i < _data[0] * 2; i += 2)
			{
				_data[i] = reinterpret_cast<int>(new str(*reinterpret_cast<str*>(a._data[i])));
				_data[i + 1] = reinterpret_cast<int>(new value(*reinterpret_cast<value*>(a._data[i + 1])));
			}
		}
		else if (isArray())
		{
			_data[0] = a._data[0];
			for (int i = 0; i < _data[0]; ++i)
			{
				_data[i + 1] = reinterpret_cast<int>(new value(*reinterpret_cast<value*>(a._data[i + 1])));
			}
		}
		else
		{
			_mem_copy(a._data, _data, a._allocated);
		}
	}
	value::~value(void) 
	{
		int i = 1;
		if (isObject())
		{
			for (; i < _data[0] * 2; i += 2)
			{
				delete reinterpret_cast<str*>(_data[i]);
				delete reinterpret_cast<value*>(_data[i + 1]);
			}
		}
		else if (isArray())
		{
			for (; i < _data[0]; ++i);
			{
				delete reinterpret_cast<value*>(_data[i]);
			}
		}
		free(_data); 
	}

	value::operator bool(void)
	{
		if (isBoolean()) return ((bool*)_data)[0];
		//consider string being 'true'
		return false;
	}
	value::operator str(void)
	{
		if (isString()) return *((str*)_data[0]);
		return "";
	}
	value::operator const char *(void)
	{
		if (isString()) return ((str*)_data[0])->c_str();
		return "";
	}
	value::operator float(void)
	{
		if (isNumber()) return ((float*)_data)[0];
		return 0xFFC00000;	//Quiet NaN
	}
	
	value & value::operator =(bool a)
	{
		_convertTo(boolean);
		_data[0] = (int)a;
		return *this;
	}
	value & value::operator =(float a)
	{
		_convertTo(number);
		((float*)_data)[0] = a;
		return *this;
	}
	value & value::operator =(const char * a)
	{
		if (isString())
		{
			((str*)_data)[0] = (str)a;
			return *this;
		}
		_convertTo(string);
		_data[0] = reinterpret_cast<int>(new str(a));
		return *this;
	}
	value & value::operator =(const str & a)
	{
		if (isString())
		{
			((str*)_data)[0] = (str)a;
			return *this;
		}
		_type = string;
		_convertTo(string);
		_data[0] = reinterpret_cast<int>(new str(a));
		return *this;
	}
	value & value::operator =(const value & a) 
	{ 
		_convertTo(a._type);
		_mem_assert(a._allocated);
		_mem_copy(a._data, _data, a._allocated);
		//Copy
		return *this;
	}

	value & value::operator [](int i)
	{
		if (isArray())
		{
			if (i > _data[0] - 1) return _null; 
			return *reinterpret_cast<value*>(_data[i + 1]);
		}
		else if (isObject())
		{
			if ((int)i > _data[0] - 1) return _null;
			return *reinterpret_cast<value*>(_data[(i + 1) * 2]);
		}
		return _null;
	}
	value & value::operator [](const char * a)
	{		
		return (*this)[str(a)];
	}
	value & value::operator [](const str & a)
	{
		//could convert to object
		if (isArray()) ;
		if (!isObject()) return _null;
		for (int i = 1; i < _data[0] * 2; i += 2)
		{
			if ((reinterpret_cast<str*>(_data[i]))->compare(a) == 0) 
			{
				return *reinterpret_cast<value*>(_data[i + 1]);
			}
		}
		_mem_assert(((_data[0] * 2) + 3) * 4);
		_data[(_data[0] * 2) + 1] = reinterpret_cast<int>(new str(a));
		_data[(_data[0] * 2) + 2] = reinterpret_cast<int>(new value());
		++_data[0];
		return *reinterpret_cast<value*>(_data[(_data[0] * 2)]);
	}

	int value::add(const char * key, const value & data)
	{
		return add(str(key), data);
	}
	int value::add(const str & key, const value & data)
	{
		_convertTo(object);
		//could convert to object
		if (!isObject()) return -1;
		_mem_assert(((_data[0] * 2) + 3) * 4);
		_data[(_data[0] * 2) + 1] = reinterpret_cast<int>(new str(key));
		_data[(_data[0] * 2) + 2] = reinterpret_cast<int>(new value(data));
		++_data[0];
		return _data[0];
	}
	int value::add(const value & data)
	{
		//could convert to array
		_convertTo(array);
		if (!isArray()) return -1;
		_mem_assert((_data[0] + 2) * 4);
		value * tmp = new value(data);
		float o = *tmp;
		_data[_data[0] + 1] = reinterpret_cast<int>(tmp);
		o = *((value*)_data[_data[0] + 1]);
		++_data[0];
		return _data[0];
	}

	int value::count(void) const
	{
		if (isArray() || isObject()) return _data[0];
		if (isNull()) return 0;
		return 1;
	}

	str & value::keyAt(int i)
	{
		if (isObject())
		{
			if ((int)i > _data[0] - 1) return *reinterpret_cast<str*>(0);
			return *reinterpret_cast<str*>(_data[(i * 2) + 1]);
		}
		return *reinterpret_cast<str*>(0);
	}
	value & value::valueAt(int i)
	{
		return (*this)[i];
	}

	
	bool value::containsKey(const char * key)
	{
		return containsKey(str(key));
	}
	bool value::containsKey(const str & key)
	{
		if (!isObject()) return false;
		for (int i = 0; i < _data[0]; ++i)
		{
			if (key.compare(*reinterpret_cast<str*>(_data[(i * 2) + 1])) == 0)
			{
				return true;
			}
		}
		return false;
	}

	void value::_convertTo(type t)
	{
		if (t == _type) return;
		if (isArray() || isObject())
		{

		}
		else if (!isNull())
		{
			delete (void*)_data[0];
		}
		_type = t;
		if (isArray())
		{
			_data[0] = 0;
		}
		else if (isObject())
		{
			_mem_assert(16);
			_data[0] = 0;
		}
	}
}
